package com.ldf.jrtsp.socket;

import com.ldf.jrtsp.enums.MediaType;
import com.ldf.jrtsp.exception.JRtspException;
import com.ldf.jrtsp.player.RtspPlayer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.*;

import static com.ldf.jrtsp.constants.RtspConstants.RTP_MAX_MTU;
import static com.ldf.jrtsp.constants.RtspConstants.RTSP_KEEP_ALIVE_DATA;

/**
 * rtcp over udp
 *
 * @author lidaofu
 * @since 2024/6/20
 **/
public class RtcpOverUdp implements IRtspSocket, Runnable {
    private final static Logger log = LoggerFactory.getLogger(RtcpOverUdp.class);
    private final RtspPlayer rtspPlayer;
    private int rtcpPort;
    private MediaType mediaType;
    private DatagramSocket datagramSocket;
    private SocketAddress senderAddress;
    private byte[] receiveData = new byte[RTP_MAX_MTU]; // 缓冲区

    public RtcpOverUdp(int rtcpPort, RtspPlayer rtspPlayer, MediaType type) {
        this.rtcpPort = rtcpPort;
        this.mediaType = type;
        this.rtspPlayer = rtspPlayer;
        try {
            RtspTransportFactory.removeRtspPort(rtcpPort);
            this.datagramSocket = new DatagramSocket(rtcpPort);
            log.info("rtcp over udp init success, port:{}", rtcpPort);
        } catch (SocketException e) {
            log.error("rtcp over udp init error", e);
            throw new JRtspException("rtcp over udp init error", e);
        }
    }

    @Override
    public void setRemoteAddress(String remoteHost, int remotePort) {
        this.senderAddress = new InetSocketAddress(remoteHost, remotePort);
        send(RTSP_KEEP_ALIVE_DATA);
    }

    @Override
    public void send(byte[] data) {
        DatagramPacket sendPacket = new DatagramPacket(data, data.length, this.senderAddress);
        try {
            datagramSocket.send(sendPacket); // 发送数据包
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 接收数据
     */
    @Override
    public void receiveData() {
        DatagramPacket receivePacket = new DatagramPacket(receiveData, RTP_MAX_MTU);
        while (!datagramSocket.isClosed()) {
            try {
                synchronized (this) {
                    datagramSocket.receive(receivePacket);
                }
                int length = receivePacket.getLength();
                if (length > 0) {
                    log.debug("receive data length:{}", length);
                }
            } catch (Exception e) {
                log.error("receive data error", e);
                throw new JRtspException("receive data error", e);
            }
        }

    }

    @Override
    public void close() {
        if (datagramSocket != null && !datagramSocket.isClosed()) {
            synchronized (this) {
                this.datagramSocket.close();
            }
        }
        RtspTransportFactory.removeRtspPort(rtcpPort);
    }

    @Override
    public void run() {
        receiveData();
    }
}
